#ifndef __IO_1061S__H
#define __IO_1061S__H

#include "bsp.h"
#include "can_controller.h"

#define MAX_REG_DEV_NUMS            6

#define DEFAULT_COMM_OVERTIME_MS	500

#define DEFAULT_OUPUT_STATE         0xFFFFFF    //默认24bit皆高
#define INDEX_IO_STATE              0x2000      //设置及回应输入输出IO状态
#define INDEX_IO_DEFAULT            0x2001      //设置IO默认的安全输出状态(掉线,初上电时输出)
#define INDEX_COM_OVERTIME	        0x2002      //设置IO子板超时重启时间
#define INDEX_GET_OUTPUT	        0x2003      //获取IO子板输出状态
#define INDEX_SET_PULSE 	        0x2004      //IO子板脉冲配置
#define INDEX_GET_PULSE 	        0x2005      //获取IO子板脉冲数状态
#define INDEX_SET_PULSE_ZERO_PIN 	0x2006      //设置零点和脉冲计数引脚
#define INDEX_SET_DEV_DRIVER_PIN 	0x2007      //设置机构控制引脚
#define INDEX_SET_DEV_MOVE_TIME 	0x2008      //设置机构移动时间
#define INDEX_SET_DEV_MOVE_POS   	0x2009      //设置机构移动位置
#define INDEX_GET_ENCODER 	        0x200A      //获取IO子板注册设备编码器值
#define INDEX_CLEAR_ENCODER 	    0x200B      //清除IO子板注册设备编码器值

typedef void (*event_callback_t)(uint8_t board_id, uint8_t event_id, void *event_data);

enum{
    EVENT_LINK = 0,
    EVENT_INPUT_CHANGE,
};

typedef enum {
	SET_PULSE_MODE = 0,
	CLEAR_PULSE_VALUE,
} SUB_INDEX_CMD_t;

typedef struct{
    union
    {
        struct{
            uint8_t is_init         : 1;
            uint8_t is_online       : 1;
            uint8_t ack_default_out : 1;
            uint8_t ack_over_time   : 1;
            uint8_t ack_get_pulse   : 1;
            uint8_t ack_set_pulse   : 1;
            uint8_t ack_set_move_time : 1;
            uint8_t ack_set_move_pos  : 1;
            uint8_t ack_get_output  : 1;
            uint8_t ack_get_encoder : 1;
            uint8_t ack_clear_encoder : 1;
            uint8_t reserve         : 5;
        };
        uint8_t flags;
    };

    uint8_t     step;               // 用于临时插入配置命令

    uint32_t    node_id;            // 节点 id

    uint32_t    default_out;        // io 子板默认输出状态（需要调用接口下发至子板）
    uint32_t    over_time;          // io 子板通信超时时间（需要调用接口下发至子板）

    uint32_t    get_pulse_pin_id;
    uint32_t    set_pulse_pin_id;
    uint32_t    pulse_result;
    uint8_t     getEncDevId;        //获取编码器的设备ID
    int32_t     devEncoder;         //设备编码器值
    uint8_t     dev_id;             //设备id
    uint8_t     direction;          //移动方向        
    uint32_t    move_time;          //控制设备移动时间
    uint32_t    move_pos;           //控制设备移动位置
    SUB_INDEX_CMD_t sub_index;

    uint32_t    output;             // io 子板输出状态（该状态为主板设置的状态，非真实的读子板IO状态）
    uint32_t    outputReal;         // io 子板输出状态（该状态为真实读子板的IO状态）
    uint32_t    input;              // io 子板输入状态

    uint64_t    timeStamp;          // 记录最近一次的通信时间戳

    aos_queue_t *rx_queue;          // 数据接收队列
	event_callback_t callback;      // io 事件回调

} io_1061s_t;

/**
 * @brief       io 子板驱动初始化
 * @param[in]	pNode_list          子板 id 列表（驱动中会将 id 变换成符合 canopen 的标准，此列表无需静态，驱动会拷贝）
 * @param[in]	list_size           id 列表长度
 * @param[in]	callback            io 子板事件回调函数
 * @return      bool                执行结果
 */
extern bool io_1061s_init(io_1061s_t *const pdev, uint8_t list_size, event_callback_t callback);
/**
 * @brief       设置 io 子板输出状态
 * @param[in]	board_id            io 子板索引 id（以 0 开始）
 * @param[in]	state               输出状态，以 bit 位代表每个 io 的电平
 * @return      int                 0：成功， -1：失败
 */
extern int io_1061s_set_output_pins(uint8_t board_id, uint32_t state);
/**
 * @brief       获取 io 子板输出状态
 * @param[in]	board_id            io 子板索引 id（以 0 开始）
 * @param[out]	pResult             输出结果，以 bit 位代表每个 io 的电平
 * @return      int                 0：成功， -1：失败
 */
extern int io_1061s_get_output_pins(uint8_t board_id, uint32_t *pResult);
//获取io子板输出的真实状态
extern int io_1061s_get_output_pins_real(uint8_t board_id, uint32_t *pResult);
/**
 * @brief       获取 io 子板输入状态
 * @param[in]	board_id            io 子板索引 id（以 0 开始）
 * @param[in]	pResult             输出结果，以 bit 位代表每个 io 的电平
 * @return      int                 0：成功， -1：失败
 */
extern int io_1061s_get_input_pins(uint8_t board_id, uint32_t *pResult);
/**
 * @brief       设置 io 子板默认输出状态(注意初始化后不可紧接着设置，此时可能还不在线)
 * @param[in]	board_id            io 子板索引 id（以 0 开始）
 * @param[in]	state               默认输出状态，以 bit 位代表每个 io 的电平
 * @return      int                 0：成功， -1：失败
 */
extern int io_1061s_set_default_output(uint8_t board_id, uint32_t state);
/**
 * @brief       设置 io 子板超时时间(注意初始化后不可紧接着设置，此时可能还不在线)
 * @param[in]	board_id            io 子板索引 id（以 0 开始）
 * @param[in]	time_ms             超时时间（ms，超过此时间，IO 子板将会重启）
 * @return      int                 0：成功， -1：失败
 */
extern int io_1061s_set_over_time(uint8_t board_id, uint32_t time_ms);

/**
 * @brief       获取指定板id的指定pinId的脉冲数
 * @param[in]	board_id            
 * @param[in]	pin_id              
 * @param[in]	pResult             
 * @return      int                 
 */
extern int io_1061s_get_pulse(uint8_t board_id, uint8_t pin_id, uint32_t * const pResult);

/**
 * @brief       设置指定板id的指定io为记脉冲模式
 * @param[in]	board_id            
 * @param[in]	pin_bit_id          需要设置记脉冲模式的io，相应比特位置1
 * @return      int                 
 */
extern int io_1061s_set_pulse(uint8_t board_id, uint32_t pin_bit_id, SUB_INDEX_CMD_t index);

/**
 * @brief       配置控制设备的IO
 * @param[in]	board_id            子板id
 * @param[in]	dev_id              注册的设备id
 * @param[in]	data                配置数据
 * @return      int                 
 */
extern int _io_1061s_config_dev_crl_pin(uint8_t board_id, uint8_t dev_id, uint32_t data);

/**
 * @brief       设置管理设备的移动时间
 * @param[in]	board_id            子板id
 * @param[in]	dev_id              注册的设备id
 * @param[in]	dir                 移动方向（>0为正向，=0停止，<0反向）
 * @param[in]	time_ms             移动时间
 * @return      int                 
 */
extern int io_1061s_set_dev_move_time(uint8_t board_id, uint8_t dev_id, int8_t dir, uint32_t time_ms);

/**
 * @brief       设置管理设备的移动位置
 * @param[in]	board_id            子板id
 * @param[in]	dev_id              注册的设备id
 * @param[in]	time_ms             移动位置
 * @return      int                 
 */
extern int io_1061s_set_dev_move_pos(uint8_t board_id, uint8_t dev_id, int32_t move_pos);

/**
 * @brief       获取管理设备的编码器值
 * @param[in]	board_id            子板id
 * @param[in]	dev_id              注册的设备id
 * @param[in]	pResult             
 * @return      int                 
 */
extern int io_1061s_get_dev_encoder(uint8_t board_id, uint8_t dev_id, int32_t * const pResult);

extern bool get_set_move_time_flag(void);
extern bool get_set_move_pos_flag(void);
extern bool get_encoder_flag(void);
extern void get_can_data_cnt(uint32_t *txCnts, uint32_t *rxCnts, uint8_t boadrdId);

#endif